/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#pragma once


#include <向量.h>
#include <矩阵.h>
#include <文件/file_载入保存数据.h>
#include <字符串转换.h>

#include <map>

#include "Mesh.h"
#include "字符串数值互换.h"
#include "引擎数据类型.h"
#include "core/动画/an_曲线.h"
#include "底层绘图/底层绘图框架.h"
#include "材质/S_Material.h"






enum E_笔刷类型 {
	e_单色填充,
	e_单色描边,
	e_单色边面,
	e_圆公切链接线,
	e_单色纹理,
	e_纹理,
	e_条纹,
	e_色轮,
	e_渐变,
	e_噪波,
};





typedef struct {
	vec2	begin_coord;
	vec2	control_coord;
	vec2	end_coord;
	float32	radius;				//线端圆弧半径
	float32 link_successively;	//线连接循序  从输出到输入或从输入到输出
}S_连接线坐标参数;

typedef struct {
	mat3X2*	coord;
	uint32* color;
	int32*	text;
	bool	GPU参数重置;
}S_sf_文字GPU参数映射;

typedef struct {
	mat3X2* p变换;
	uvec2*	p图元;
	uint32* p颜色;
	bool	GPU参数重置;
}S_sf_单色GPU映射;
typedef struct {
	S_VkDrawIndirectCommand*	p间接;
	mat3X2*						p变换;
	uint32*						p颜色;
	S_LineProp*					p线属性;
}S_sf_GPU映射面单色;



typedef struct {
	mat3X2* coord;
	uvec2* p图元;
	uint32* pEColor;
	uint32* pColor;
	bool	GPU参数重置;
}S_sf_单色边面GPU映射;

typedef struct {
	mat3X2* pCoord;
	uvec2* p图元;
	uvec2* pColor;
	bool	GPU参数重置;
}S_sf_纹理面GPU映射;

typedef struct {
	mat3X2*	pCoord;
	uint32*	pColor;
	uint32*	pICO_UV;
}S_sf_图标GPU映射;









typedef struct {
	float32 相交距离;
	float32 相交点到起点距离;
	int32	线索引;
}S_线拾取;

typedef struct {
	vec3    相交坐标;
	float32 相交距离;
	int32	面索引;
}S_面拾取;





typedef struct {
	S_板载缓存* 属性;
	S_GPU内存块索引* 变换;
	S_GPU内存块索引* 颜色;
	S_GPU内存块索引* 线属性;
	S_GPU内存块索引* 纹理属性;

	suvec2		m_属性ID;

	uint32		层;
	bool		链接属性;
	bool		链接变换;
	bool		链接颜色;
	bool		链接线属性;

	bool		链接纹理属性;

}S_凸边图元;

typedef struct {
	S_板载缓存*      属性;
	bool		     链接属性;
	S_GPU内存块索引* 变换;
	bool		     链接变换;
	S_GPU内存块索引* 颜色;
	bool		     链接颜色;
	S_GPU内存块索引* 渐变;
	bool		     链接渐变;
	uint32		     层;
}S_渐变图元;







struct S_Surface {
	//S_VBO		m_顶点数据;
	//S_顶点缓存*	m_顶点缓存;
	//S_Material*	m_材质;
	S_Surface();
	void		f_Draw点();
};
typedef void(*f_Draw_Surface3D)(S_设备环境& ctx);

typedef struct {
	S_帧缓存*		m_帧缓存;
	//S_渲染环境*		m_绘图配置;
	S_纹理*			m_Color[3];
	S_纹理*			m_Depth[2];

	S_纹理采样器*	m_Smaple;

	S_设备环境*		m_Ctx;

	uint8			m_交换ID;

}S_Surface3D;

S_Surface3D* f_surface_Create(S_设备环境& Ctx3D, const uvec2& size);

bool f_surface_改变大小(S_Surface3D* face, const uvec2& size);
void f_surface_Release(S_Surface3D* face);




typedef void(*fp_Surface2D元素变换属性)(void* v, uint32 num);

struct S_字体加载参数 {
	//std::vector<suvec2>	m_编码区间;
	std::vector<uint32> m_编码区间;
	std::string         m_字体名称;
	uint16              m_字号;
	std::string         m_名称;
	
};



struct S_Font {
	S_纹理*							m_Tex;
	S_板载缓存*						m_uv偏移;
	std::vector<S_Rectf>			m_区域;
	
	uint16							m_字号;

	//std::map<wchar_t, uint16>		m_字符外部编码映射内部编码;
	//std::vector<uint16>    m_字符外部编码映射内部编码;
	//uint16	operator [] (wchar_t name) { return m_Name[name]; }
	//uint16	f_从外部编码取内部编码 (wchar_t name) const { 
	//	return m_字符外部编码映射内部编码.at(name);
	//}
	uint16	f_get字符宽度(wchar_t name) const {
		if (name == '\t') return m_字号 * 2;
		//auto it = m_字符外部编码映射内部编码.at(name);
		return m_区域[name].宽度;
	}
};

struct S_TexArrayRes {
	S_纹理* m_Tex;
	std::map<std::string, uint16> m_Name;

	uint16 operator [] (const std::string name) { return m_Name[name]; }
};





typedef struct {
	S_材质*			m_材质;
	
	S_板载缓存**	m_参数元素;
	S_纹理**		m_纹理参数;
	uint8*			m_GPU绑定位置;

	uint16			m_参数元素数量;
	uint16			m_纹理参数数量;
	//S_TexArrayRes* m_纹理库对象;	
	//S_结构对象指针	m_GPU参数set;
}S_2D笔刷;




typedef struct {
	vec2 m_比例;
	vec2 m_偏移;
	//uint32 m_顶点数量;
	int32 m_渐变数量;
	int32 m_间隔;
}S_2D顶点属性;


//typedef struct {
//	vec2 coord;
//	vec2 weights;
//}S_2D元素顶点;


//typedef struct {
//	suvec2 m_顶点;
//	suvec2 m_变换;
//	suvec2 m_属性;
//}S_2D元素区间;

//typedef struct {
//	vec4*	m_Data;
//	uint32	m_Num;
//}S_2D变换数据指针;


typedef struct {
	S_2D笔刷*	字体笔刷;
	//和 S_单色文本绘制ID id_文本 是同一个
	uint16		文本ID;
	uint16		区间大小;
}S_2D文本对象;








struct S_Widget绘制材质 {
	S_材质* m_单色凸边形填充;
	S_材质* m_单色凸边形描边;

	S_材质* m_单色描边;
	S_材质* m_渐变描边;
	S_材质* m_单色填充;
	S_材质* m_渐变填充;




	S_材质* m_单纹理;
	S_材质* m_间接单色填充;
	S_材质* m_间接单色描边;
	S_材质* m_动态线;

	S_材质* m_曲线点;
	S_材质* m_曲线;
	S_材质* m_色轮;
	S_材质* m_渐变;
	S_材质* m_多曲线;


	S_材质* m_线性渐变填充;
	S_材质* m_2线性渐变填充;
	S_材质* m_3线性渐变填充;
	

	S_材质* m_点控渐变填充;
	S_材质* m_2点控渐变填充;
	S_材质* m_矢量线;
	S_材质* m_表格线;



	S_材质* m_过程纹理描边;
	S_材质* m_过程纹理填充;
	S_材质* m_外部纹理描边;
	S_材质* m_外部纹理填充;

	S_材质* m_公切园链接线;
	S_材质* m_连接点笔;
	S_材质* m_临时连接线笔;
	S_材质* m_单色图标笔刷;
	S_材质* m_纯纹理图标笔刷;
	S_材质* m_文本笔刷;
	S_材质* m_文本块笔刷;
	S_材质* m_边缘阴影;



	S_材质* m_条纹笔刷材质;
	S_材质* m_条纹填充;
	S_材质* m_棋盘格填充;
	S_材质* m_网格填充;
	S_材质* m_渐变背景纹理填充;
	S_材质* m_棋盘格背景纹理填充;


	S_材质* m_刻度线;
	S_材质* m_网格刻度线;
	//S_材质* m_表格线;




	S_纹理采样器* m_采样器;

	std::map<std::string, S_TexArrayRes>	m_ICOs;
	std::map<std::string, S_Font>			m_Fonts;

	
	S_Widget绘制材质(S_设备环境& Ctx, E_MS次数 msCount);

};

struct S_Widget预设图元 {
	static uvec2	m_矩形;
	static uvec2	m_左圆角矩形;
	static uvec2	m_右圆角矩形;

	static uvec2	m_上圆角矩形;
	static uvec2	m_下圆角矩形;
	static uvec2	m_圆角矩形;
	static uvec2	m_左上圆角矩形;
	static uvec2	m_右上圆角矩形;
	static uvec2	m_圆形;

	static uvec2	m_竖向圆角连接线;
	static uvec2	m_横向圆角连接线;
	static uvec2	m_竖向斜角连接线;
	static uvec2	m_横线;
	static uvec2	m_竖线;
	static uvec2	m_斜线;
	static uvec2	m_生成C形左拐角连接线;
	static uvec2	m_生成C形右拐角连接线;
	static uvec2	m_生成L形下拐角连接线;
	static uvec2	m_生成L形上拐角连接线;
};




struct S_UI创建环境 {
	S_设备环境			m_Ctx;
	S_Widget绘制材质*	m_Mat;

	//一定要注意 m_图元ID.y 是记录的也是全局偏移 而不是当前区间顶点数量
	static S_Widget预设图元          m_图元ID;
	static std::vector<S_2D图元顶点> m_预设图元顶点;

	E_MS次数			m_采样数;
	uint8				m_DPI;

	S_UI创建环境(S_设备环境& ctx, E_MS次数 msCount);
	~S_UI创建环境();

	std::vector<C_Widget*> m_3DViewScene;

	static void f_初始化预设图元();
	static void f_销毁绘图资源();

	//弃用
	uint16				m_文字字号;
};








typedef struct {
	S_GPU内存块索引  m_顶点;
	S_GPU内存块索引  m_索引;
	S_GPU内存块索引  m_间接;
	
	std::string		m_纹理;
	S_2D笔刷		m_笔刷;
	
	uint32			m_实例数量;
	uint32			m_实例偏移;
	uint32			m_顶点数量;
	uint32			m_顶点偏移;
	
	//uint16			m_类型数量;
	float32			m_线宽;
	
	bool			m_是否引用;
}S_Surface2D;



struct S_2D画布 {
	S_设备环境	m_Ctx;
	int16						m_绘制推进层;
	
	std::vector<S_板载缓存*>	m_属性;
	std::vector<S_板载缓存*>	m_扩展GPU参数;

	std::vector<S_Surface2D>	m_surf;
	
	S_板载缓存*					m_父级画布属性;
	
	S_Widget绘制材质*			m_调色板;

	//static S_板载缓存*			m_预设图元顶点;
	static S_板载缓存*		 m_间接绘制图元顶点;
	static S_板载缓存*       g变换GPU缓存;

	static S_板载缓存*       g字符GPU缓存;
	static S_板载缓存*       g行文本变换GPU缓存;
	static S_板载缓存*       g行文本颜色GPU缓存;

	static S_板载缓存*       g表格变换GPU缓存;
	static S_板载缓存*       g表格颜色GPU缓存;

	static S_板载缓存*       g顶点;
	static S_板载缓存*       g索引;
	static S_板载缓存*       g间接;

	static S_板载缓存*       g凸包变换;
	static S_板载缓存*       g凸包颜色;
	static S_板载缓存*       g凸包线属性;
	static S_板载缓存*       g凸包纹理属性;
	static S_板载缓存*       g凸包渐变属性;
	static S_板载缓存*       g凸包渐变控制属性;
	static S_板载缓存*       g凸包色轮属性;

	static S_板载缓存*       g图标变换;
	static S_板载缓存*       g图标颜色;

	static S_板载缓存*       g纹理变换;
	static S_板载缓存*       g纹理属性;

	static S_板载缓存*        g线段;

	//同时用于多个部件同时引用同一画布
	bool						m_是否重绘;

	S_2D画布(S_设备环境& ctx);
	~S_2D画布();

	//virtual void	f_Update(S_渲染参数& 参数);
	virtual void	f_绘制到屏幕(S_渲染参数& 参数);
	

	void	f_清除绘制数据();
	void	f_清除多余绘制面();
};



inline void f_initSurface2D(S_Surface2D* face, S_设备环境& m_Ctx) {
	face->m_顶点 = f_buf_alloc(S_2D画布::g顶点, 0);
	face->m_索引 = f_buf_alloc(S_2D画布::g索引, 0);
	face->m_间接 = f_buf_alloc(S_2D画布::g间接, 0);

	face->m_笔刷 = {};
	
	face->m_线宽 = 0.0;
	face->m_顶点数量 = 0;
	face->m_顶点偏移 = 0;
	face->m_实例数量 = 0;
	face->m_实例偏移 = 0;
}

inline void f_releaseSurface2D(S_Surface2D* face) {
	if (face->m_笔刷.m_参数元素数量) free(face->m_笔刷.m_参数元素);
	face->m_笔刷.m_参数元素数量 = 0;

	if (face->m_笔刷.m_纹理参数) free(face->m_笔刷.m_纹理参数);
	face->m_笔刷.m_纹理参数数量 = 0;

	free(face->m_笔刷.m_GPU绑定位置);

	face->m_笔刷.m_参数元素 = nullptr;
	face->m_笔刷.m_纹理参数 = nullptr;

	f_buf_erase(face->m_顶点);
	f_buf_erase(face->m_索引);
	f_buf_erase(face->m_间接);
	(*face) = {};
}

/*inline void f_surface_清除画布层(S_Surface2D* face) {
	f_buf_erase(face->m_顶点);
	f_buf_erase(face->m_索引);
	f_buf_erase(face->m_间接);
	
	free(face->m_笔刷.m_参数元素);
	free(face->m_笔刷.m_纹理参数);
	free(face->m_笔刷.m_GPU绑定位置);
	face->m_笔刷 = {};
}*/



void				f_surface_加载字体(S_UI创建环境& ctx, const S_字体加载参数& 字体参数);


uint16				f_surface_get字符串宽度T(const S_Font& font, std::wstring text, float32 gap);
uint16				f_surface_get字符串宽度(const S_Font& font, std::wstring text, float32 gap);
uint16				f_surface_get字符串宽度(const S_Font& font, wchar_t text, float32 gap);


inline const S_Font&	f_surface_get字体库(S_UI创建环境& ctx, std::string name) {
	name += "_" + f_整数值转字符串(ctx.m_文字字号);
#ifdef _DEBUG  

#endif
	if (name == "晴圆等宽_12") {
		ctx.m_Mat->m_Fonts;
	}
	if (ctx.m_Mat->m_Fonts.find(name) == ctx.m_Mat->m_Fonts.end()) {
		return ((ctx.m_Mat->m_Fonts.begin()->second));
	}
	
	return ctx.m_Mat->m_Fonts[name];
}

inline const S_Font& f_surface_get字体库(S_UI创建环境& ctx, std::string name, std::string 字号) {
	name += "_" + 字号;
#ifdef _DEBUG  
	if (name == "晴圆等宽_12") {
		ctx.m_Mat->m_Fonts;
	}
	if (ctx.m_Mat->m_Fonts.find(name) == ctx.m_Mat->m_Fonts.end()) {
		return ((ctx.m_Mat->m_Fonts.begin()->second));
	}
#endif
	return ctx.m_Mat->m_Fonts[name];
}

Inline const S_Font& f_surface_get字体(S_UI创建环境& ctx, std::string name) {
	name += "_" + f_整数值转字符串(ctx.m_文字字号);
#ifdef _DEBUG  
	if (name == "晴圆等宽_12") {
		ctx.m_Mat->m_Fonts;
	}
	if (ctx.m_Mat->m_Fonts.find(name) == ctx.m_Mat->m_Fonts.end()) {
		return ((ctx.m_Mat->m_Fonts.begin()->second));
	}
#endif
	return ctx.m_Mat->m_Fonts[name];
}

Inline const S_Font& f_surface_get字体(S_2D画布* 画布, std::string name, uint32 字号) {
	name += "_" + f_整数值转字符串(字号);
#ifdef _DEBUG 
	if (name == "晴圆等宽_12") {
		画布->m_调色板->m_Fonts;
	}
	if (画布->m_调色板->m_Fonts.find(name) == 画布->m_调色板->m_Fonts.end()) {
		return ((画布->m_调色板->m_Fonts.begin()->second));
	}
#endif
	return 画布->m_调色板->m_Fonts[name];
}


#define DEF_IDget笔刷(画布, ID)  (画布)->m_笔刷[(ID)]




uint32 f_mesh_gen间接绘制网格属性(S_Mesh* mesh, uint32 num);
uint32 f_mesh_resize间接绘制网格属性(S_Mesh* mesh, uint32 num);
void f_mesh_set间接绘制网格属性(S_Mesh* mesh, const S_MeshTranformProp& prop, uint32 offset = 0);
void f_mesh_set绘制属性(S_Mesh* mesh, const S_MeshDrawProp& prop);



//bool f_surface_Gpu射线拾取网格_坐标_法线_UV(S_Mesh* mesh, const Mat44f& mat, float32 独立缩放, const vec3& s, const vec3& dir, vec3& 交点, float32& min距离);





